package com.mrzhou.data.support;

import com.fasterxml.jackson.core.type.TypeReference;
import com.mrzhou.core.tool.utils.ClassUtil;
import com.mrzhou.core.tool.utils.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.Jedis;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 将redisTemplate封装Redis的操作工具类
 */
@Slf4j
public class RedisService {

    private StringRedisTemplate redisTemplate;

    public RedisService(StringRedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}

    /**
     * 获取指定key超时时间, 时间精度: 秒
     */
    public Long expire(String key) {
        return redisTemplate.getExpire(key);
    }

    public void remove(final String... keys) {
       redisTemplate.delete(Arrays.asList(keys));
    }

    public void remove(final String key) {
        if(exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 批量删除key
     */
    public void removePattern(final String pattern) {
        Set<String> keys = redisTemplate.keys(pattern); // 查询前缀为xxx的所有key
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }

    /**
     * 判断缓存中是否有对应的value
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 获取缓存中保存的数据
     */
    public String get(final String key) {
        return redisTemplate.opsForValue().get(key);
    }

    public <T> T get(final String key, Class<T> type) {
        try{
            String json = redisTemplate.opsForValue().get(key);
            return JacksonUtil.parseObject(json, type);
        } catch (Exception e) {
            log.error("获取数据失败，{}", e);
            return null;
        }
    }

    /**
     *  如保存复杂的json格式, 则使用fastJson解析,
     */
    public <T> T get(final String key, TypeReference<T> type) {
        try{
            String json = redisTemplate.opsForValue().get(key);
            return JacksonUtil.parseObject(json, type);
        } catch (Exception e) {
            log.error("获取数据失败，{}", e);
            return null;
        }
    }

    public boolean set(final String key, String value) {
        try{
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            log.error("缓存数据失败，{}", e);
            return false;
        }
    }

    public boolean set(final String key, String value, Long expireTime) {
        try {
            redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            log.error("缓存数据失败，{}", e);
            return false;
        }
    }

    public boolean set(final String key, Object obj) {
        try{
            redisTemplate.opsForValue().set(key, JacksonUtil.toJsonString(obj));
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public boolean set(final String key, Object obj, Long expireTime) {
        try{
            redisTemplate.opsForValue().set(key, JacksonUtil.toJsonString(obj));
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public boolean hmSet(final String key, Map<String, ?> map) {
        try{
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            log.error(e.getLocalizedMessage());
            return false;
        }
    }

    /**
     * 指定向redis中的hash添加一个key
     */
    public boolean hmSetKey(String hashKey, String key, Object value) {
        boolean result = false;
        try {
            redisTemplate.opsForHash().put(hashKey, key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     *  获取hash 指定key包含的全部数据
     */
    public <T> Map<String, T>  hmGet(String key, Class<T> type) {
        Map<String, T> resultMap = new HashMap<>();
        try{
            Map<Object, Object>  map = redisTemplate.opsForHash().entries(key);
            Optional.ofNullable(map).ifPresent(var1 -> {
                for(Map.Entry<Object, Object> var2: var1.entrySet()) {
                    if(var2.getValue() instanceof Map) {
                        resultMap.put(String.valueOf(var2.getKey()), (T) ClassUtil.toBean((Map)var2.getValue(), type));
                    } else {
                        resultMap.put(String.valueOf(var2.getKey()), (T) var2.getValue());
                    }
                }
            });
            return resultMap;
        } catch (Exception e) {
            log.error("获取数据失败，{}", e);
        }
        return resultMap;
    }

    public <T> T hmGetKey(String hashKey, String key, Class<T> type) {
        try{
            Object obj = redisTemplate.opsForHash().get(hashKey, key);
            return JacksonUtil.parseObject(String.valueOf(obj), type);
        } catch (Exception e) {
            log.error("获取数据失败，{}", e);
            return null;
        }
    }

    /**
     * 判断hm结构是否包含存在的key
     * @param hmKey hm-key
     * @param key
     * @return
     */
    public boolean hmExists(String hmKey, String key) {
        return ObjectUtils.isNotEmpty(redisTemplate.opsForHash().get(hmKey, key));
    }

    /**
     * 删除hm结构中指定的key
     * @param hmKey
     * @param key
     */
    public void hmRemove(String hmKey, String key) {
        redisTemplate.opsForHash().delete(hmKey, key);
    }

    public boolean tryLock() {
        Jedis jedis = new Jedis();
        return true;
    }

}
